package horncomb.bpm.process.def.state;

import horncomb.bpm.BpmContextHolder;
import horncomb.bpm.process.core.EnterableState;
import horncomb.bpm.process.core.ExecutionContext;
import horncomb.bpm.process.core.LeavableState;
import horncomb.bpm.process.core.Transition;
import horncomb.bpm.process.def.TansitionException;

import java.io.Serializable;
import java.util.List;

/**
 * @author Daniel
 */
public class DefaultStateDefinition extends AbstractStateDefinition implements
		Serializable, LeavableState, EnterableState {
	private static final long serialVersionUID = 6960058613385706449L;

	public DefaultStateDefinition(String id) {
		super();
		this.id = id;
	}

	public boolean hasLeavingTransitions() {
		return this.getProcessDefinition().hasLeavingTransitions(this.id);
	}

	/**
	 * {@inheritDoc}
	 */
	public List<Transition> getLeavingTransitions() {
		return this.getProcessDefinition().findLeavingTransitions(this.id);
	}

	public boolean checkBeforEntering(ExecutionContext context) {
		return true;
	}

	/**
	 * {@inheritDoc}
	 */
	public void enter(ExecutionContext context) {
		if (!this.checkBeforEntering(context)) {
			throw new TansitionException("State cannot be entering.", context
					.getToken(), context.getTransition(), this);

		}
		this.doEnter(context);
		if (context.getTransition() != null) {
			// has assign next transition
			context.getTransition().transit(context);
		}
	}

	protected void doEnter(ExecutionContext context) {
		context.getToken().setState(this);
		BpmContextHolder.getContext().getProcessManagementService().update(
				context.getToken());
	}

	public boolean checkBeforeLeaving(ExecutionContext context) {
		return (context.getTransition() != null);
	}

	/**
	 * {@inheritDoc}
	 */
	public void leave(ExecutionContext context) {
		if (!this.checkBeforeLeaving(context)) {
			throw new TansitionException("State cannot be leaving.", context
					.getToken(), context.getTransition(), this);
		}
		this.doLeave(context);
	}

	protected void doLeave(ExecutionContext context) {
		context.getToken().setState(null);
		BpmContextHolder.getContext().getProcessManagementService().update(
				context.getToken());
	}
}
